package com.t.bricks.bussiness.service.bridge;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.http.client.utils.URIUtils;
import org.mitre.dsmiley.httpproxy.ProxyServlet;

import com.t.bricks.model.Log;
import com.t.bricks.model.MsgEmity;
import com.t.bricks.utils.function.json.JacksonShell;
import com.t.bricks.utils.function.url.URLUtil;

/**
 * 请求代理服务
 * @author huangxinbian
 */
public class ProxyServletEx extends ProxyServlet {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -3339069579325354256L;

	/**
	 * 
	 */
	private static Map<String, Object[]> serverSiteMap = null;
	
	/**
	 * Cloud注册中心地址(分布式时使用)
	 */
	private static String cloudCenterUrl = null;
	
	/**
	 * Cloud注册中心用户名(分布式时使用)
	 */
	private static String cloudCenterUser = null;
	
	/**
	 * Cloud注册中心用户密码(分布式时使用)
	 */
	private static String cloudCenterPass = null;

	/**
	 * 分布式程序'请求代理'信息,注意:启用此配置则不再访问注册中心查找服务,即cloud.center的配置无效
	 */
	private static String cloudProxyDomains = null;

	/**
	 * 序列锁集合
	 */
	private static Map<String, Object> mapLock = null;
	
	/**
	 * 序列锁引用计数值集合,当值为0时同时清理'序列锁集合'
	 */
	private static Map<String, Integer> mapLockCount = null;
	
	/**
	 * 设置
	 * @param url
	 * @param user
	 * @param pass
	 * @param domains
	 */
	public static void setCloudCenterUrl(String url, String user, String pass, String domains) {
		cloudCenterUrl = url;
		cloudCenterUser = user;
		cloudCenterPass = pass;
		cloudProxyDomains = domains;
		
		if (null == cloudProxyDomains || "".equals(cloudProxyDomains.trim())) {
			serverSiteMap = new ConcurrentHashMap<>(10);
			mapLock = new ConcurrentHashMap<String, Object>(5);
			mapLockCount = new ConcurrentHashMap<String, Integer>(5);
			return;
		}
		
		String[] array = cloudProxyDomains.split(";");
		serverSiteMap = new ConcurrentHashMap<>(array.length);
		for (String string : array) {
			if (null == string || "".equals(string.trim())) {
				continue;
			}
			
			String[] temp = string.split("\\|");
			if (temp.length < 2) {
				continue;
			}
			
			serverSiteMap.put(temp[0], new Object[] { temp[1], null });
		}
	}
	
	/**
	 * 访问注册中心,获取服务地址
	 * @param serverName
	 * @return
	 */
	private String findServerSite(String serverName) {
		if (serverSiteMap.containsKey(serverName)) {
			Object[] info = serverSiteMap.get(serverName);
			if (null == info[1]) {
				return (String)info[0];//说明永久有效
			}
			
			if ((System.currentTimeMillis() - (Long)info[1]) < 60000) {//60000=1分钟
				return (String)info[0];//有效期内
			}
		}
		
		if (null != cloudProxyDomains && !"".equals(cloudProxyDomains)) {
			Log.error("启用的固定代理信息'cloud.proxy.domains'中没有对应的代理信息:", serverName);
			return "";
		}

		if (null == cloudCenterUrl || "".equals(cloudCenterUrl.trim())) {
			Log.error("项目未配置注册中心地址,配置项'cloud.center.site'");
			return "";
		}
		
		Object lockObj = null;//锁标识

		synchronized (this) {
			lockObj = mapLock.get(serverName);//获取对象锁
			if (null == lockObj) {
				lockObj = new Object();
				mapLock.put(serverName, lockObj);
				mapLockCount.put(serverName, 1);//计数值
			} else {
				mapLockCount.put(serverName, mapLockCount.get(serverName) + 1);//计数值+1
			}
		}

		synchronized (lockObj) {
			try {
				//--先再检查一遍--//
				if (serverSiteMap.containsKey(serverName)) {
					Object[] info = serverSiteMap.get(serverName);
					if ((System.currentTimeMillis() - (Long)info[1]) < 60000) {//60000=1分钟
						return (String)info[0];//有效期内
					}
				}
				
				//--查询--//
				String url = String.format("http://%s/find/name?sName=%s&sUser=%s&key=%s",
						cloudCenterUrl, serverName, cloudCenterUser, cloudCenterPass)
						.replace("http://http://", "http://");
				MsgEmity me = URLUtil.get(url);
				if (!me.isSuccess()) {
					Log.error(me.getMsg());
					return "";
				}
				
				MsgEmity result = JacksonShell.toJavaObject(me.getData(), MsgEmity.class);
				if (null == result) {
					Log.error("访问注册中心失败,未能获取预期信息");
					return "";
				}
				
				if (!result.isSuccess()) {
					if (result.getData() instanceof Integer) {
						Log.error(me.getMsg());
						return "";
					}
		
					Log.error(result.getMsg());
					return "";
				}
				
				Map<String, Object> map = JacksonShell.toJavaObject(result.getData(), Map.class);//{"success":true,"msg":"找到数据","data":"{\"sSign\":\"TBaseSystemServer\",\"serverPort\":\"9002\",\"serverIp\":\"192.168.56.1\"}"}
				
				String str = String.format("http://%s:%s", map.get("serverIp"), map.get("serverPort"));
				
				serverSiteMap.put(serverName, new Object[] { str, System.currentTimeMillis() });
				
				return str;
			} finally{
				mapLockCount.put(serverName, mapLockCount.get(serverName) - 1);//计数值-1
				if (mapLockCount.get(serverName) < 1) {//计数值为0,剔除
					mapLockCount.remove(serverName);
					mapLock.remove(serverName);
				}
			}
		}
	}

	/**
	 * 访问代理
	 * @param request
	 * @param response
	 */
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String domainName = request.getHeader("domainName");
		if (null == domainName || "".equals(domainName.trim())) {
			domainName = request.getHeader("domainname");
		}
		
		String targetUri = findServerSite(domainName);
		if (null == targetUri || "".equals(targetUri.trim())) {
			return;
		}
		
		request.setAttribute(ATTR_TARGET_URI, null);
		super.targetUri = targetUri;

		URI uri = null;
		try {
			uri = new URI(targetUri);
		} catch (URISyntaxException e) {
			Log.error("创建URI对象出错, targetUri[{}]", targetUri, e);
		}
		
		request.setAttribute(ATTR_TARGET_HOST, null);
		super.targetHost = URIUtils.extractHost(uri);

		super.service(request, response);
	}

}
